using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml.Serialization;
using Google.GData.Client;
using Google.GData.CodeSearch;
using SubversionReports.Entities;
using Match=System.Text.RegularExpressions.Match;

namespace SubversionReports.Utilities
{
    public static class Google
    {
        /// <summary>
        /// Gets the repository summary file path.
        /// </summary>
        /// <value>The repository summary file path.</value>
        public static string RepositorySummaryFilePath
        {
            get { return string.Format("{0}Logs{1}GoogleCodeRepositoryList.xml", HttpContext.Current.Request.PhysicalApplicationPath, (HttpContext.Current.Request.PhysicalApplicationPath.StartsWith("/") ? "/" : "\\")); }
        }

        /// <summary>
        /// Codes the search.
        /// </summary>
        /// <param name="searchTerm">The search term.</param>
        /// <returns></returns>
        public static List<Repository> CodeSearch(string searchTerm)
        {
            List<Repository> repositoryList = new List<Repository>();
            CodeSearchService myService = new CodeSearchService("SubversionReports.org");
            //http://www.google.com/codesearch/feeds/search?q=
            //http://www.google.co.uk/search?num=100&as_sitesearch=code.google.com%2Fp%2F&safe=off
            CodeSearchFeed resultFeed = myService.Query(new FeedQuery(string.Format("http://code.google.com/hosting/search?q={0}", searchTerm)));
            foreach (CodeSearchEntry atomEntry in resultFeed.Entries)
            {
                Repository repository = new Repository();
                repository.Url = atomEntry.PackageElement.Uri;
                repository.Description = atomEntry.Title.Text;
                repositoryList.Add(repository);
            }
            return repositoryList;
        }

        /// <summary>
        /// Googles the search.
        /// </summary>
        /// <returns></returns>
        public static List<Repository> GoogleSearch()
        {
            List<Repository> repositoryList = new List<Repository>();
            List<string> distinctProjects = new List<string>();
            for (int i = 0; i < 1000; i += 100)
            {
                string query = "http://www.google.co.uk/search?q=+site:code.google.com/p/&num=100&hl=en&safe=off&start=" + i + "&sa=N";
                StreamReader reader = new StreamReader(SvnWebDav.GetResponseStream(new Uri(query), null));
                string markup = reader.ReadToEnd();
                Regex regex = new Regex(@"http:\/\/code\.google\.com\/p\/([a-z]*)");
                System.Text.RegularExpressions.MatchCollection matches = regex.Matches(markup);
                if (matches.Count > 0)
                {
                    foreach (Match match in matches)
                    {
                        string project = match.Captures[0].Value.Replace("http://code.google.com/p/", string.Empty);
                        if (!distinctProjects.Contains(project))
                        {
                            try
                            {
                                distinctProjects.Add(project);
                                Repository repository = new Repository();
                                repository.Url = string.Format("http://{0}.googlecode.com/svn/", project);
                                repository.Description = string.Format("{0} Revisions", SvnWebDav.GetLastRevisionNumber(repository.Url, string.Empty, string.Empty));
                                repositoryList.Add(repository);
                            }
                            catch { ; }
                        }
                    }
                }
            }
            return repositoryList;
        }

        /// <summary>
        /// Appends the random entries.
        /// </summary>
        /// <param name="repositoryList">The repository list.</param>
        public static void AppendRandomEntries(List<RepositorySummary> repositoryList)
        {
            List<RepositorySummary> newEntries = RandomProjectSearch();
            newEntries.ForEach(delegate(RepositorySummary summary) { if (repositoryList.Find(delegate(RepositorySummary existing) { return existing.RootUrl.Equals(summary.RootUrl); }) == null) { repositoryList.Add(summary); } });
            repositoryList.Sort(delegate(RepositorySummary rs1, RepositorySummary rs2) { return rs2.RevisionCount.CompareTo(rs1.RevisionCount); });
            CacheRepositoryList(repositoryList);
        }

        /// <summary>
        /// Updates the repository summary.
        /// </summary>
        /// <param name="repositorySummary">The repository summary.</param>
        public static void UpdateRepositorySummary(RepositorySummary repositorySummary)
        {
            int i = 0;
            int index = -1;
            List<RepositorySummary> repositorySummaryList = GetRepositoryListFromCache();
            repositorySummaryList.ForEach(delegate (RepositorySummary summary) { if(summary.RootUrl.Equals(repositorySummary.RootUrl)) { index = i; } i++; });
            if(!index.Equals(-1))
            {
                repositorySummaryList[index].Contributors = repositorySummary.Contributors;
                repositorySummaryList[index].LastQueried = repositorySummary.LastQueried;
                repositorySummaryList[index].LastRevised = repositorySummary.LastRevised;
                repositorySummaryList[index].RevisionCount = repositorySummary.RevisionCount;
            }
            else
            {
                repositorySummaryList.Add(repositorySummary);
                repositorySummaryList.Sort(delegate(RepositorySummary rs1, RepositorySummary rs2) { return rs2.RevisionCount.CompareTo(rs1.RevisionCount); });
            }
            CacheRepositoryList(repositorySummaryList);
        }

        /// <summary>
        /// Randoms the project search.
        /// </summary>
        /// <returns></returns>
        private static List<RepositorySummary> RandomProjectSearch()
        {
            Random RandNum = new Random();
            string alphabet = "abcdefghijklmnopqrstuvwxyz";

            string query = "http://www.google.co.uk/search?q=site:code.google.com/p/+" + alphabet[RandNum.Next(25)] + "&num=10&start=" + (RandNum.Next(99) * 10);

            List<RepositorySummary> repositoryList = new List<RepositorySummary>();
            StreamReader reader = new StreamReader(SvnWebDav.GetResponseStream(new Uri(query), null));
            string markup = reader.ReadToEnd();
            Regex regex = new Regex(@"http:\/\/code\.google\.com\/p\/([a-z]*)");
            System.Text.RegularExpressions.MatchCollection matches = regex.Matches(markup);
            if (matches.Count > 0)
            {
                foreach (Match match in matches)
                {
                    string project = match.Captures[0].Value.Replace("http://code.google.com/p/", string.Empty);
                    try
                    {
                        RepositorySummary repositorySummary = new RepositorySummary();
                        repositorySummary.RootUrl = string.Format("http://{0}.googlecode.com/svn/", project);
                        repositorySummary.RevisionCount = SvnWebDav.GetLastRevisionNumber(repositorySummary.RootUrl, string.Empty, string.Empty);
                        repositorySummary.LastQueried = DateTime.Now;
                        repositoryList.Add(repositorySummary);
                    }
                    catch { ; }
                }
            }
            return repositoryList;
        }

        /// <summary>
        /// Caches the repository list.
        /// </summary>
        /// <param name="repositoryList">The repository list.</param>
        private static void CacheRepositoryList(List<RepositorySummary> repositoryList)
        {
            if (System.IO.File.Exists(RepositorySummaryFilePath)) System.IO.File.Delete(RepositorySummaryFilePath);
            XmlSerializer serializer = new XmlSerializer(typeof(List<RepositorySummary>));
            TextWriter textWriter = new StreamWriter(RepositorySummaryFilePath);
            serializer.Serialize(textWriter, repositoryList);
            textWriter.Close();
        }

        /// <summary>
        /// Gets the repository list from cache.
        /// </summary>
        /// <returns></returns>
        public static List<RepositorySummary> GetRepositoryListFromCache()
        {
            if (System.IO.File.Exists(RepositorySummaryFilePath))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(List<RepositorySummary>));
                TextReader textReader = new StreamReader(RepositorySummaryFilePath);
                List<RepositorySummary> cachedRepositoryList = (List<RepositorySummary>)serializer.Deserialize(textReader);
                textReader.Close();
                return cachedRepositoryList;
            }
            return new List<RepositorySummary>();
        }
    }
}
